# -*- coding: utf-8 -*-
from functools import wraps
import datetime
import StringIO
import os
import sys

from flask import *
import mongoengine

import forms

sys.path.append('..')
sys.path.append('../..')
from core import model
from core.model import Admin, UserDevRelate, UserDev, User, Device, StarAward, StepAward, DevData, Maprecord, SOS, Loger
from core.packet import getlist, interact, reduceAudio, findimei
from agent.alphabet import OK
from core.cache import redis
from core.tools import dumps
import setting

admin = Blueprint('admin', __name__, static_folder='static', template_folder='templates')


def request_login(fun):
    @wraps(fun)
    def check_login(*args, **kwargs):
        token = request.cookies.get('tokens')
        userid = request.cookies.get('client')
        if token and userid:
            utoken = redis.hget('Admin:' + userid, 'token')
            if token == utoken:
                return fun(*args, **kwargs)
        return render_template('login')

    return check_login


def validate_form(forms):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            g.form = forms(request.form)
            if g.form.validate():
                return func(*args, **kwargs)
            else:
                return abort(401)

        return wrapper

    return decorator


@admin.route('/login', methods=['POST'])
@validate_form(forms.login)
def login():
    username = g.form.username.data
    password = g.form.password.data
    new_password = g.form.new_password.data
    try:
        user = Admin.objects(username=username, password=password).get()
    except mongoengine.DoesNotExist:
        return 'no'
    userid = str(user.id)
    if new_password:
        user.password = new_password
        user.save()
        return 'ok'
    token = os.urandom(24).encode('base64')
    redis.hset('Admin:' + userid, 'token', token)
    resp = make_response('ok')
    resp.set_cookie('tokens', token, max_age=43200)
    resp.set_cookie('client', userid, max_age=43200)
    return resp


@admin.route('/logout', methods=['POST'])
def logout():
    if request.cookies.get('tokens'):
        resp = make_response('200')
        resp.set_cookie('tokens', '', expires=0)
        resp.set_cookie('client', '', expires=0)
        return resp
    return '200'


@admin.route('/', methods=['GET', 'POST'])
@request_login
def index():
    if request.method == 'GET':
        now = datetime.datetime.now().strftime('%Y年%m月%d日').decode('utf8')
        return render_template('index', time=now)


@admin.route('/Menu', methods=['POST'])
@request_login
def Menu():
    token = request.cookies.get('tokens')
    userid = request.cookies.get('client')
    if not userid or not token:
        return abort(401)
    utoken = redis.hget('Admin:' + userid, 'token')
    if token != utoken:
        return abort(401)
    try:
        admin = Admin.objects(id=userid).get()
    except Admin.DoesNotExist:
        return abort(404)
    if admin.type == 'admin':
        data = [
            {'name': '数据管理', 'data': 'data'},
            {'name': '调试腕表', 'data': 'debug'}
        ]
    elif admin.type == 'debug':
        data = [
            {'name': '调试腕表', 'data': 'debug'}
        ]
    else:
        data = [
            {'name': '数据管理', 'data': 'data'}
        ]
    return dumps(data)


seniorMenuDict = {
    'data': [
        {'name': '关系管理', 'data': 'relateInfo'},
        {'name': '用户管理', 'data': 'userInfo'},
        {'name': '宝贝数据', 'data': 'babyInfo'},
        {'name': '宝贝家庭圈', 'data': 'babyFamily'},
        {'name': '宝贝管理', 'data': 'babyManage'},
        {'name': '宝贝星星', 'data': 'starInfo'},
        {'name': '宝贝运动', 'data': 'stepInfo'},
        {'name': '宝贝定位', 'data': 'amapInfo'},
        {'name': 'sos记录', 'data': 'sosInfo'}
    ],
    'debug': [
        {'name': '在线终端', 'data': 'onlineTerminal'},
        {'name': '腕表日志', 'data': 'loggerTerminal'}
    ]
}


@admin.route('/seniorMenu', methods=['POST'])
@request_login
@validate_form(forms.menu)
def seniorMenu():
    try:
        return dumps(seniorMenuDict[g.form.data.data])
    except KeyError:
        return ''


@admin.route('/minorMenu/<menu>', methods=['GET'])
@request_login
def minorMenu(menu):
    return render_template('menu/' + menu)


@admin.route('/getdevicelist', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def getdevicelist():
    page = g.form.page.data if g.form.page.data else 0
    try:
        result = getlist(page, g.form.num.data)
        return result
    except:
        return ''


@admin.route('/getdeviceone', methods=['POST'])
@request_login
def getdeviceone():
    imei = request.form.get('imei')
    if imei:
        result = findimei(imei)
        if result == OK:
            return json.dumps({'len': 1, 'list': [imei]})
        else:
            return json.dumps({'len': 0, 'list': []})
    else:
        return ''


@admin.route('/emit', methods=['POST'])
@request_login
@validate_form(forms.emit)
def emit():
    try:
        params = g.form.params.data.split(',') if g.form.params.data else []
        result = interact(g.form.imei.data, g.form.instruct.data, params)
    except Exception, e:
        result = repr(e)
    return result


@admin.route('/logger/<imei>', methods=['POST'])
@request_login
def logger(imei):
    data = []
    if 'logger' not in session or 'status' in request.form:
        for l in Loger.objects(model='server', ident=imei).order_by('-id').limit(20):
            data.append({'event': l.event, 'value': l.value, 'time': l.time})
        session['logger'] = datetime.datetime.now()
    else:
        for l in Loger.objects(model='server', ident=imei, time__gt=session['logger']).order_by('-id'):
            data.append({'event': l.event, 'value': l.value, 'time': l.time})
        session['logger'] = datetime.datetime.now()
    return dumps(data)


@admin.route('/logger/totalpage/<imei>', methods=['POST'])
@request_login
def loggertotalpage(imei):
    num = Loger.objects(model='server', ident=imei).count()
    return dumps(num)


@admin.route('/logger/find/<imei>/<int:page>/<int:num>', methods=['POST'])
@request_login
def loggerfind(imei, page, num):
    data = []
    for l in Loger.objects(model='server', ident=imei).order_by('-id').limit(num).skip(page * num):
        data.append({'event': l.event, 'value': l.value, 'time': l.time})
    return dumps(data)


@admin.route('/sendaudio', methods=['POST'])
@request_login
def sendaudio():
    audioIO = StringIO.StringIO()
    request.files['audio'].save(audioIO)
    audioIO.seek(0)
    result = reduceAudio(request.form['imei'], audioIO)
    return result


# -------------------------------------------------------------------------------------------------
@admin.route('/babyrelatelist/<option>', methods=['POST'])
@request_login
@validate_form(forms.babyrelatelist)
def babyrelatelist(option):
    value = g.form.value.data
    if value == 'family':
        return 'family 为系统关键字,不可以添加'
    relate = g.form.relate.data
    try:
        r = UserDevRelate.objects(value=value, relate=relate).get()
        if option == 'delete':
            try:
                r.delete()
                model.relatewrite += 1
            except mongoengine.OperationError:
                return 'no'
            return 'success'
        else:
            r.relate = relate
            r.save()
            model.relatewrite += 1
            return 'success'
    except mongoengine.DoesNotExist:
        UserDevRelate(relate=relate, value=value).save()
        model.relatewrite += 1
        return 'success'


@admin.route('/babyrelateupload/<filename>', methods=['POST'])
@request_login
def babyrelateupload(filename):
    try:
        request.files['portrait'].save('./admin/static/relate/' + filename + ".png")
        model.updateRelatePortrait()
    except:
        return 'no'
    return 'success'


# -------------------------------------------------------------------------------------------------
def makeUserList(count, result):
    userlist = []
    for i in result:
        babylist = []
        for userdev in UserDev.objects(user=i).only('dev'):
            babylist.append(getattr(userdev.dev, 'imei', ''))
        userlist.append({
            'userid': i.id,
            'phone': i.phone,
            'email': i.email if i.email else '',
            'password': i.password,
            'token': i.token[:10] + '...' if len(i.token) > 13 else i.token,
            'maketime': i.maketime,
            'lasttime': i.lasttime,
            'model': i.model,
            'baby': '<br/>'.join(babylist),
            'admin': i.admin,
            'relateInfo': i.relateInfo,
        })
    return dumps({'list': userlist, 'len': count})


@admin.route('/getuserlist', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def getuserlist():
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    count = User.objects.only('id').count()
    result = User.objects.order_by('-id').limit(num).skip(page * num)
    return makeUserList(count, result)


@admin.route('/User_order/<column>/<order>', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def userorder(column, order):
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    count = User.objects.only('id').count()
    if order == 'asc':
        result = User.objects.order_by(column).limit(num).skip(page * num)
    else:
        result = User.objects.order_by('-' + column).limit(num).skip(page * num)
    return makeUserList(count, result)


@admin.route('/User_search/<column>/<value>', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def usersearch(column, value):
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    count = User.objects(**{column + '__contains': value}).only('id').count()
    result = User.objects(**{column + '__contains': value}).limit(num).skip(page * num)
    result = result if result else ()
    count = count if count else 0
    return makeUserList(count, result)


@admin.route('/User_modify/<userid>/<column>/<value>', methods=['POST'])
@request_login
def usermodify(userid, column, value):
    user = User.objects(id=userid).first()
    if user:
        setattr(user, column, value)
        user.save()
    return 'success'


@admin.route('/deleteUser', methods=['POST'])
@request_login
def deleteUser():
    try:
        user = User.objects(id=request.form['userid']).get()
        user.delete()
    except User.DoesNotExist:
        return '用户未找到'
    return '删除成功'


# -------------------------------------------------------------------------------------------------
def makeDeviceList(count, result):
    devlist = []
    for i in result:
        devlist.append({
            'imei': i.imei,
            'maketime': i.maketime,
            'lasttime': i.lasttime,
            'name': i.name,
            'age': i.age,
            'height': i.height,
            'weight': i.weight,
            'sex': i.sex if i.sex else setting.default['sex'],
            'steplen': i.steplen,
            'voltage': i.voltage,
            'phone': i.phone,
            'localinterval': i.localintervalminute if i.localintervalminute else 10
        })
    return dumps({'list': devlist, 'len': count})


@admin.route('/getbabylist', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def getbabylist():
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    count = Device.objects.only('imei').count()
    result = Device.objects.order_by('-lasttime').limit(num).skip(page * num)
    return makeDeviceList(count, result)


@admin.route('/Device_order/<column>/<order>', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def deviceorder(column, order):
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    count = Device.objects.only('imei').count()
    if order == 'asc':
        result = Device.objects.order_by(column).limit(num).skip(page * num)
    else:
        result = Device.objects.order_by('-' + column).limit(num).skip(page * num)
    return makeDeviceList(count, result)


@admin.route('/Device_search/<column>/<value>', methods=['POST'])
@validate_form(forms.getlist)
@request_login
def devicesearch(column, value):
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    count = Device.objects(**{column + '__contains': value}).only('imei').count()
    result = Device.objects(**{column + '__contains': value}).limit(num).skip(page * num)
    result = result if result else ()
    count = count if count else 0
    return makeDeviceList(count, result)


@admin.route('/Device_modify/<imei>/<column>/<value>', methods=['POST'])
@request_login
def devicemodify(imei, column, value):
    dev = Device.objects(imei=imei).first()
    if dev:
        setattr(dev, column, value)
        dev.save()
    return 'success'


@admin.route('/deleteDevice', methods=['POST'])
@request_login
def deleteDevice():
    try:
        dev = Device.objects(imei=request.form['imei']).get()
        dev.delete()
    except User.DoesNotExist:
        return '宝贝未找到'
    return '删除成功'


# -------------------------------------------------------------------------------------------------
def makeDeviceFamilyList(count, result):
    devlist = []
    for i in result:
        family = []
        member = UserDev.objects(dev=i).order_by('time')
        for userdev in member:
            family.append({
                'admin': True if userdev.type == 'admin' else False,
                'id': userdev.user.id,
                'relate': userdev.relate.value,
                'time': userdev.time
            })
        devlist.append({
            'imei': i.imei,
            'family': family,
        })
    return dumps({'list': devlist, 'len': count})


@admin.route('/getbabyfamilylist', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def getbabyfamilylist():
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    count = Device.objects.only('imei').count()
    result = Device.objects.order_by('imei').limit(num).skip(page * num)
    return makeDeviceFamilyList(count, result)


@admin.route('/DeviceFamily_order/<column>/<order>', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def devicefamilyorder(column, order):
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    count = Device.objects.only('imei').count()
    if order == 'asc':
        result = Device.objects.order_by(column).limit(num).skip(page * num)
    else:
        result = Device.objects.order_by('-' + column).limit(num).skip(page * num)
    return makeDeviceFamilyList(count, result)


@admin.route('/DeviceFamily_search/<column>/<value>', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def devicefamilysearch(column, value):
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    count = Device.objects(**{column + '__contains': value}).only('imei').count()
    result = Device.objects(**{column + '__contains': value}).limit(num).skip(page * num)
    result = result if result else ()
    count = count if count else 0
    return makeDeviceFamilyList(count, result)


@admin.route('/deleteRelate', methods=['POST'])
@request_login
@validate_form(forms.userbaby)
def deleteRelate():
    try:
        imei = g.form.imei.data
        userdev = UserDev.objects(user=g.form.userid.data, dev=imei).get()
        userdev.delete()
    except UserDev.DoesNotExist:
        return '关系未找到'
    return '删除成功'


# -------------------------------------------------------------------------------------------------
def makeDeviceManageList(count, result):
    devlist = []
    for i in result:
        saferegion = []
        for region in i.saferegion:
            saferegion.append({
                'id': region.id,
                'name': region.name,
                'address': region.address,
                'radius': region.radius,
                'lon': region.lon,
                'lat': region.lat
            })
        silent = []
        for s in i.silent:
            silent.append({
                'num': s.num,
                'weekday': s.weekday,
                'starttime': s.starttime.strftime('%H:%M'),
                'endtime': s.endtime.strftime('%H:%M'),
            })
        devlist.append({
            'imei': i.imei,
            'saferegion': saferegion,
            'silent': silent
        })
    return dumps({'list': devlist, 'len': count})


@admin.route('/getbabymanagelist', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def getbabymanagelist():
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    count = Device.objects.only('imei').count()
    result = Device.objects.order_by('imei').limit(num).skip(page * num)
    return makeDeviceManageList(count, result)


@admin.route('/DeviceManage_order/<column>/<order>', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def devicemanageorder(column, order):
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    count = Device.objects.only('imei').count()
    if order == 'asc':
        result = Device.objects.order_by(column).limit(num).skip(page * num)
    else:
        result = Device.objects.order_by('-' + column).limit(num).skip(page * num)
    return makeDeviceManageList(count, result)


@admin.route('/DeviceManage_search/<column>/<value>', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def devicemanagesearch(column, value):
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    count = Device.objects(**{column + '__contains': value}).only('imei').count()
    result = Device.objects(**{column + '__contains': value}).limit(num).skip(page * num)
    result = result if result else ()
    count = count if count else 0
    return makeDeviceManageList(count, result)


# -------------------------------------------------------------------------------------------------
def makeStarList(count, result):
    starlist = []
    for i in result:
        starlist.append({
            'id': i.id,
            'target': i.target,
            'star': i.star,
            'award': i.award,
            'starttime': i.starttime,
            'endtime': i.endtime if i.endtime else '00-00-00 00:00:00',
            'done': i.done,
        })
    return dumps({'list': starlist, 'len': count})


@admin.route('/Star_order/<identcolumn>/<ident>/<column>/<order>', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def starorder(identcolumn, ident, column, order):
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    count = StarAward.objects(**{identcolumn: ident}).only('id').count()
    if order == 'asc':
        result = StarAward.objects(**{identcolumn: ident}).order_by(column).limit(num).skip(page * num)
    else:
        result = StarAward.objects(**{identcolumn: ident}).order_by('-' + column).limit(num).skip(page * num)
    return makeStarList(count, result)


@admin.route('/Star_search/<column>/<value>', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def starsearch(column, value):
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    result = StarAward.objects(**{column: value}).order_by('-id').limit(num).skip(page * num).all()
    count = StarAward.objects(**{column: value}).only('id').count()
    result = result if result else ()
    count = count if count else 0
    return makeStarList(count, result)


@admin.route('/Star_modify/<sid>/<column>/<value>', methods=['POST'])
@request_login
def starmodify(sid, column, value):
    star = StarAward.objects(id=sid).first()
    if star:
        setattr(star, column, value)
        star.save()
    return 'success'


# -------------------------------------------------------------------------------------------------
def makeDataList(count, result):
    datalist = []
    for i in result:
        j = StepAward.objects(
            **{'dev': i.dev, 'starttime__gte': i.date, 'starttime__lt': i.date + datetime.timedelta(days=1)}).first()
        datalist.append({
            'id': i.id,
            'target': j.target if j else '',
            'step': i.step,
            'distance': i.distance,
            'calories': i.calories,
            'date': i.date,
            'done': j.done if j else '',
        })
    return dumps({'list': datalist, 'len': count})


@admin.route('/Data_order/<identcolumn>/<ident>/<column>/<order>', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def dataorder(identcolumn, ident, column, order):
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    count = DevData.objects(**{identcolumn: ident}).count()
    if order == 'asc':
        result = DevData.objects(**{identcolumn: ident}).order_by(column).limit(num).skip(page * num)
    else:
        result = DevData.objects(**{identcolumn: ident}).order_by('-' + column).limit(num).skip(page * num)
    return makeDataList(count, result)


@admin.route('/Data_search/<column>/<value>', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def datasearch(column, value):
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    result = DevData.objects(**{column: value}).order_by('-id').limit(num).skip(page * num)
    count = DevData.objects(**{column: value}).only('id').count()
    result = result if result else ''
    count = count if count else 0
    return makeDataList(count, result)


@admin.route('/Data_modify/<did>/<column>/<value>', methods=['POST'])
@request_login
def datamodify(did, column, value):
    data = DevData.objects(id=did).first()
    if data:
        setattr(data, column, value)
        data.save()
    return 'success'


# -------------------------------------------------------------------------------------------------
def makeAmapList(count, result):
    maplist = []
    for i in result:
        maplist.append({
            'lon': i.lon,
            'lat': i.lat,
            'province': i.province,
            'city': i.city,
            'road': i.road,
            'poi': i.poi,
            'address': i.address,
            'radius': i.radius,
            'time': i.time,
            'useGPS': i.useGPS,
            'rawLon': i.rawLon,
            'rawLat': i.rawLat,
        })
    return dumps({'list': maplist, 'len': count})


@admin.route('/Amap_order/<identcolumn>/<ident>/<column>/<order>', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def amaporder(identcolumn, ident, column, order):
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    count = Maprecord.objects(**{identcolumn: ident}).only('id').count()
    if order == 'asc':
        result = Maprecord.objects(**{identcolumn: ident}).order_by(column).limit(num).skip(page * num)
    else:
        result = Maprecord.objects(**{identcolumn: ident}).order_by('-' + column).limit(num).skip(page * num)
    return makeAmapList(count, result)


@admin.route('/Amap_search/<column>/<value>', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def amapsearch(column, value):
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    result = Maprecord.objects(**{column: value}).order_by('-id').limit(num).skip(page * num)
    count = Maprecord.objects(**{column: value}).only('id').count()
    result = result if result else ()
    count = count if count else 0
    return makeAmapList(count, result)


@admin.route('/Amap_modify/<mid>/<column>/<value>', methods=['POST'])
@request_login
def amapmodify(aid, column, value):
    amap = Maprecord.objects(id=aid).first()
    if amap:
        setattr(amap, column, value)
        amap.save()
    return 'success'


# -------------------------------------------------------------------------------------------------
def makeSOSList(count, result):
    soslist = []
    for i in result:
        soslist.append({
            'id': i.id,
            'address': i.address,
            'time': i.time,
        })
    return dumps({'list': soslist, 'len': count})


@admin.route('/SOS_order/<identcolumn>/<ident>/<column>/<order>', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def sosorder(identcolumn, ident, column, order):
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    count = SOS.objects(**{identcolumn: ident}).only('id').count()
    if order == 'asc':
        result = SOS.objects(**{identcolumn: ident}).order_by(column).limit(num).skip(page * num)
    else:
        result = SOS.objects(**{identcolumn: ident}).order_by('-' + column).limit(num).skip(page * num)
    return makeSOSList(count, result)


@admin.route('/SOS_search/<column>/<value>', methods=['POST'])
@request_login
@validate_form(forms.getlist)
def sossearch(column, value):
    page = g.form.page.data if g.form.page.data else 0
    num = g.form.num.data
    result = SOS.objects(**{column: value}).order_by('-id').limit(num).skip(page * num)
    count = SOS.objects(**{column: value}).only('id').count()
    result = result if result else ()
    count = count if count else 0
    return makeSOSList(count, result)


@admin.route('/SOS_modify/<sid>/<column>/<value>', methods=['POST'])
@request_login
def sosmodify(sid, column, value):
    sos = SOS.objects(id=sid).first()
    if sos:
        setattr(sos, column, value)
        sos.save()
    return 'success'
